﻿using System.Collections.Generic;

namespace LightPersist.Transactions
{
	/// <summary>
	/// Store all actions occured in the certain amount of time
	/// </summary>
	internal class Transaction
	{
		private readonly List<ActionEntry> actions;

		public virtual TransactionState State { get; internal set; }
		public virtual bool SkipDuringProcess { get; internal set; }

		internal Transaction()
		{
			actions = new List<ActionEntry>();
			State = TransactionState.Started;
		}

		private Transaction(Transaction parent)
			: this()
		{
			Parent = parent;
		}

		/// <summary>
		/// Processor are required to enforce checking of ability to change current transaction. This ability are denied during rollback/undo/redo, but it is hard to check this in every AddActionCall. This is why processor injected with parameter.
		/// </summary>
		/// <param name="action"></param>
		/// <param name="processor"></param>
		public void AddAction(TheAction action, TransactionProcessor processor)
		{
			AddActionEntrySafe(new ActionEntry(action), processor);
		}

		internal void AddActionEntrySafe(ActionEntry actionEntry, TransactionProcessor processor)
		{
			var skip = processor == null || processor.SkipCheckingAndLoggingTransaction;
			Debug.WriteLine(LoggingIndention + string.Format("  {0}+{1} ", (skip ? "(" : null), (skip ? ")" : null)) + actionEntry);
			if (!skip)
			{
				actions.Add(actionEntry);
			}
		}

		public Transaction AddChildTransaction(TransactionProcessor processor)
		{
			var childTranscation = new Transaction(this);
			AddActionEntrySafe(new ActionEntry(childTranscation), processor);
			return childTranscation;
		}

		// performed actions stored in this transaction
		public IList<ActionEntry> Actions
		{
			get { return actions.AsReadOnly(); }
		}

		public Transaction Parent { get; private set; }

		public int ParentsDeep
		{
			get { return Parent == null ? 0 : Parent.ParentsDeep + 1; }
		}

		internal string LoggingIndention
		{
			get { return new string('\t', ParentsDeep); }
		}

		public override string ToString()
		{
			return "TR" + GetHashCode() % 64;
		}
	}
}